#include "MemPool.h"
#include "aceMesh_clang.h"
#include "aceMesh_utils.h"
#include "am_machine.h"
#include "hashtable.h"
#include "scheduler.h"
#include "slave.h"
#include "task_dag_graph.h"
#include "am_assert.h"   //断言头文件
#include "utils/acelog.h"

#ifdef SLAVE_CONSTRUCT_HELEPR
#include "helper_slave.h"
extern __thread_local_fix struct slave_help_buff slave_buffer[NT];
extern __thread_local_fix int construct_end;
__thread_local_fix int helper_exited[64]={0};
// extern __thread_local_fix int helper_exited;
volatile void* vector_subtasks[VECTOR_SUBSIZE];
__thread_local_fix int subtask_num=0;

// extern volatile __thread int slave_init_done;
// extern __uncached volatile int slave_init_done=0;

#endif
#define remote_ldm(coreid,ldm_var) ((unsigned long)&ldm_var | ((unsigned long)coreid << 20 ) |(1ULL << 45))
// #ifndef SLAVE_CONSTRUCT_HELEPR
__thread_local_fix int spawn_subtask_num=0;
 volatile void* need_spawn_subtasks[NEED_SPAWN_SUBSIZE];
// #endif
//extern __thread_local_fix HashMap slave_first_level;
extern __thread_local_fix aceMesh_task *local_parent;
#ifdef ACEMESH_GRAPH_BUILD_PROFILING
extern unsigned long buil_prof[N_BUILD_PROF];
// extern int first_build_nest_graph;
// extern unsigned long nest_graph_build_start;
// extern unsigned long nest_graph_build_end;
unsigned long nest_graph_spawn_start;
int first_nest_graph_spawn;
#endif
// inline void slave_set_access_state(int val, volatile int * state)
// {
//     *state = val;
//     asm volatile("memb\n");
// }
#ifndef SLAVE_CONSTRUCT_HELEPR
inline struct new_slave_table_item * new_get_collision_buffer_item(struct new_slave_table *addresses)
{
    //printf("addresses->col_idx %d\n",addresses->col_idx );
    assert(addresses->col_idx  < COLLISION_BUF_SIZE);
       if (addresses->col_idx >= COLLISION_BUF_SIZE) {
        int i;
        int empty = 0;
        for (i = 0; i < SLAVE_TBL_SIZE; i++) {
            if (addresses->items[i].data_addr == NULL) {
                empty++;
            }
        }
        printf("empty rate: %f\n", (float)empty / SLAVE_TBL_SIZE);
        fflush(stdout);
        // assert(0);
    }
   struct new_slave_table_item * item = &(addresses->col_items[addresses->col_idx]);
    addresses->col_idx++;
    return item;
}
void add_succ(struct DataAccess *succ_access, struct DataAccess *pre_access)
{
#if defined(ACEMESH_GRAPH_BUILD_PROFILING) && defined(FINE_PROF)
    unsigned long add_succ_start=rtc();
#endif
     //printf("tbl任务类型%dtblDA地址%p任务地址%ptbl任务地址%p,\n",tbl->data_access->_type,tbl->data_access,data_access->_originator,tbl->data_access->_originator);
    if(pre_access!=NULL){
        if(pre_access->_type==IN && succ_access->_type==IN && pre_access->_accessFlags==SATISFIED){   //识别第一层，前驱是已经就绪的R，新增加剧的R也是自然就绪的，仅连接不阻塞
            slave_set_access_state(SATISFIED, &(succ_access->_accessFlags));
            // succ_access->_accessFlags=SATISFIED;  //!!!!用这种会有并发安全问题，执行结果不正确
            slave_set_unblock_Successor(pre_access,succ_access); //R1-R2,R1是top，R2为ready
           // printf("不阻塞的前驱子任务%p,后继子任务%p\n",predata_access->_originator,data_access->_originator);
         }else { // 以上三个条件，任一不满足，都说明存在实际的依赖（R-W，W-R，W-W，W-R-R），必须修改引用计数
            slave_setSuccessor(pre_access,succ_access);   
           // printf("前驱子任务%p,后继子任务%p\n",predata_access->_originator,data_access->_originator); 
        }   

    }else{
        if(succ_access->_type==IN){ //该地址没有前驱，且类型为读，则设置addr.top=true
            slave_set_access_state(1, &(succ_access->top));
            // succ_access->top=true;
       // printf("设置%p为top%d\n",data_access,data_access->top);
        }
        slave_set_access_state(SATISFIED, &(succ_access->_accessFlags));
        // succ_access->_accessFlags=SATISFIED;
    }
    //printf("设置succ\n");
#if defined(ACEMESH_GRAPH_BUILD_PROFILING) && defined(FINE_PROF)
    buil_prof[SUB_ADD_SUCC]+=(rtc()-add_succ_start);
#endif
}
#endif
// inline void set_access_state(int val, volatile int * state)
// {
//     *state = val;
//     asm volatile("memb\n");
// }
/*
void new_update_hashitem(struct DataAccess *data_access, struct new_slave_table_item *tbl)
{

    struct DataAccess *predata_access = NULL;
    if(tbl->data_access!=NULL){
        predata_access=tbl->data_access;
    }
    tbl->data_access=data_access;
     //printf("tbl任务类型%dtblDA地址%p任务地址%ptbl任务地址%p,\n",tbl->data_access->_type,tbl->data_access,data_access->_originator,tbl->data_access->_originator);
    if(predata_access!=NULL){
        if(predata_access->_type==IN && data_access->_type==IN && predata_access->_accessFlags==SATISFIED){   //识别第一层，前驱是已经就绪的R，新增加剧的R也是自然就绪的，仅连接不阻塞
            //slave_set_access_state(SATISFIED, &(data_access->_accessFlags));
            data_access->_accessFlags=SATISFIED;
            slave_set_unblock_Successor(predata_access,data_access); //R1-R2,R1是top，R2为ready
           // printf("不阻塞的前驱子任务%p,后继子任务%p\n",predata_access->_originator,data_access->_originator);
         }else { // 以上三个条件，任一不满足，都说明存在实际的依赖（R-W，W-R，W-W，W-R-R），必须修改引用计数
            slave_setSuccessor(predata_access,data_access);   
           // printf("前驱子任务%p,后继子任务%p\n",predata_access->_originator,data_access->_originator); 
        }   
         
   
    }else{
        if(data_access->_type==IN){ //该地址没有前驱，且类型为读，则设置addr.top=true
            //slave_set_access_state(1, &(data_access->top));  //此函数海洋之光无法使用，需要替换
            data_access->top=true;
       // printf("设置%p为top%d\n",data_access,data_access->top);
        }
        //slave_set_access_state(SATISFIED, &(data_access->_accessFlags));
        data_access->_accessFlags=SATISFIED;
    }

}
*/
#ifdef SLAVE_CONSTRUCT_HELEPR
void send_elem2helper(int id,struct DataAccess *access,void *address,unsigned long hash){
       // int destid=7;
        //往destid号的从核的slave_buffer里送数据信息，helepr从核选取7号之后的核
        int helper_id;
        if(HELPER_NUM==8){
            helper_id = ((hash >> 61) & 0x7)+8;     //取高3位,数据流地址映射到0-7的8个helper中
        }else if(HELPER_NUM==4){
            helper_id = ((hash >> 61) & 0x3)+8;
        }else if(HELPER_NUM==16){
            helper_id = ((hash >> 61) & 0xf)+8;  //映射给16个从核
        }else if(HELPER_NUM==1){
            helper_id=8;
        }else{
            assert(0);
        }
        
        // printf("send to bufferid%daddress%p\n",helper_id,address);
        struct slave_help_buff *self=remote_ldm(helper_id, (slave_buffer[_MYID]));
        //printf("*****发送bufferid%d****头指针%d,尾指针%d\n",_MYID,self->head,self->tail);
        //printf("##尾指针%d\n",self->tail);
        int local_tail=(self->tail+1)%HELPER_BUFF_SIZE; 
        //队列满就一直循环等待
        while(self->head==local_tail){
            
        }  
        //往环形队列里填充数据
        self->base[self->tail].item_address=address;
        self->base[self->tail].item_hash=hash;
        self->base[self->tail].item_access=access;
        self->base[self->tail].item_id=id;
        self->tail=local_tail;  //尾指针+1

}
#endif
Error_Code register_access(aceMesh_task *task)  //注册依赖关系
{
         
#ifdef SLAVE_CONSTRUCT_HELEPR
    vector_subtasks[subtask_num]= (unsigned long) task;
    subtask_num++;
    assert(subtask_num<8192);
    //  printf("ID%d\n",_MYID);
#endif
       
        // printf("ID%dtail%d\n",_MYID,slave_buffer[_MYID].tail);

    // add_end_task(t);  //延续之前的end
    aceMesh_task *parent = (aceMesh_task *)local_parent;
    if (parent != NULL) {        
        //printf("注册任务%p\n",task);                                     // nested
        slave_setparent(&(task->task_base), &(parent->task_base));  // parent为线程私有变量
        struct TaskDataAccesses *accessStruct = slave_getDataAccesses(&(task->task_base));
       // printf("accessStruct->_currentIndex%d\n",accessStruct->_currentIndex);
        for (int i = 0; i < accessStruct->_currentIndex; i++) {
            void *address = accessStruct->_addressArray[i];
            //printf("address%p\n",address);    
            struct DataAccess *access = &(accessStruct->_accessArray[i]);
            int accessType = access->_type;     
            unsigned long hash_value = (unsigned long)address * HASH_MULT_VALUE;
            slave_my_mutex_unlock(&(access->mutex_access)); //对每一个access初始化锁（必要
#ifdef SLAVE_CONSTRUCT_HELEPR
            //int domain_id=task->task_base.affinity_id;
            // int parent_id=parent->task_base.affinity_id;
            int domain_id=_MYID;
            //printf("_MYID%d,affinity_id%d,parnet_id%d\n",_MYID,domain_id,parent_id);  
            //往helper从核发送消息
            slave_send_elem2helper(domain_id, access, address, hash_value);
#else
            struct TaskDataAccesses *parentAccessStruct = slave_getDataAccesses(&(parent->task_base));
            struct DataAccess *predecessor = NULL;
           // printf("%paccess->mutex_access_before%d\n",access,access->mutex_access);
            
            int tbl_idx = 0;
            volatile struct new_slave_table *addresses = parentAccessStruct->_subaccessBottomMap;
            //unsigned long hash_value = (unsigned long)address * HASH_MULT_VALUE;
            tbl_idx = ((hash_value) >> 44) & 0xffff; ////取高20位(高位的变化更大)中的低16位，65536
             //printf("索引%d\n",tbl_idx);
            if (addresses->items[tbl_idx].data_addr == address) {  //哈希表存在地址
            //printf("哈希表存在地址\n");
                  predecessor=addresses->items[tbl_idx].data_access;
                    slave_add_succ(access, predecessor);
                     addresses->items[tbl_idx].data_access=access; //更新哈希表
                }
                else if (addresses->items[tbl_idx].data_addr == NULL) { //哈希表不存在此地址
                //printf("哈希表不存在地址\n");
                    predecessor=addresses->items[tbl_idx].data_access;
                    addresses->items[tbl_idx].data_addr = address;
                    slave_add_succ(access, predecessor);
                    addresses->items[tbl_idx].data_access=access; //更新哈希表

                }
                else {
                    //printf("哈希冲突%p\n",address);
                    struct new_slave_table_item * col_item = NULL;
                    struct new_slave_table_item * temp = &(addresses->items[tbl_idx]);
                    while (temp->succ != NULL) { 
                        //struct new_slave_table_item *temp_item=NULL;
                        //temp_item=temp->succ;
                        if (temp->succ->data_addr == address) {  
                            //slave_new_update_hashitem(access, temp->succ);
                            
                            predecessor=temp->succ->data_access;
                            slave_add_succ(access, predecessor);
                            temp->succ->data_access=access; //更新哈希表
                            goto update_complete;
                        }
                        temp = temp->succ;   
                    
                    }      
                    col_item = new_get_collision_buffer_item(addresses);    
                    temp->succ = col_item;
                    col_item->data_addr = address;
                    //slave_new_update_hashitem(access, col_item);
                    predecessor=col_item->data_access;
                    slave_add_succ(access, predecessor); //依赖边追加和前驱计数更新
                    col_item->data_access=access; //更新哈希表
                update_complete:
                    ;
              
                }
#endif
        }
       // printf("注册任务完毕%p亲和性%d\n",task,task->task_base.affinity_id);                                     // nested

       // printf("子任务前驱计数task%p,precount:%d\n",task,task->task_base._predecessorCount);
    } else {  // first level,从核不执行此部分代码
//         slave_setparent(&(task->task_base), NULL);
//         struct TaskDataAccesses *accessStruct = slave_getDataAccesses(&(task->task_base));
//         for (int i = 0; i < accessStruct->_currentIndex; i++) {
//             void *address = accessStruct->_addressArray[i];
//             struct DataAccess *access = &(accessStruct->_accessArray[i]);
//             DataAccessType accessType = access->_type;
//             // ReductionInfo *reductionInfo = nullptr;
//             struct DataAccess *predecessor = NULL;
//             // bottom_map_t &addresses=first_level;

//             bool exist = false;
//             exist = slave_hashExists(slave_first_level, address);

//             if (exist) {
//                 // Element already exists.
//                 predecessor = (struct DataAccess *)slave_hashGet(slave_first_level, address);
//             }
//             slave_hashPut(slave_first_level, address, access);
//             // struct DataAccess *parentAccess = nullptr;
//             if (predecessor != NULL) {  // 并发构图需要判断前驱任务是否结束
// #ifdef CONCURRENT_CONSTRUCT_GRAPH
//                 if (predecessor->_originator->over == false) {
//                     ((aceMesh_task *)(predecessor->_originator))->mutex_add_successor.lock();
//                     if (predecessor->_originator->over == false) {
// #endif
//                         slave_setSuccessor(predecessor, access);

// #ifdef CONCURRENT_CONSTRUCT_GRAPH
//                     }
//                     ((aceMesh_task *)(predecessor->_originator))->mutex_add_successor.unlock();
//                 }

// #endif
//                 // del_end_task(predecessor->_originator);        //需要修改
//             }
//         }
    }
#ifndef SLAVE_CONSTRUCT_HELEPR
#if defined(ACEMESH_GRAPH_BUILD_PROFILING) && defined(FINE_PROF)
                     unsigned long sub_clean_spawn=rtc();
#endif
#ifdef CONCURRENT_CONSTRUCT_GRAPH
    if (task->slave_dec_predecessorCount())
#else
    if (slave_predec_count(&(task->task_base)) == -1)  
#endif
    {
        //slave_spawn_to_id((struct task *)task);  // slave的是直接spawn，并发场景需要注意！
        need_spawn_subtasks[spawn_subtask_num] = (unsigned long)task;
        spawn_subtask_num++;
        assert(spawn_subtask_num<=NEED_SPAWN_SUBSIZE);
    }
#if defined(ACEMESH_GRAPH_BUILD_PROFILING) && defined(FINE_PROF)
                    buil_prof[SUB_PUSH_SPAWN]+=(rtc()-sub_clean_spawn);
#endif
#endif
}

Error_Code register_child_task(aceMesh_task *t)
{
#ifdef FAT_TDG
    slave_initprecount(&(t->task_base));
#endif
#if defined(ACEMESH_GRAPH_BUILD_PROFILING) && defined(FINE_PROF)
    // unsigned long add_start = rtc();
#endif
#if defined(ACEMESH_GRAPH_BUILD_PROFILING) && (defined(FINE_PROF2) || defined(FINE_PROF3))
    unsigned long find_start;
#endif
#ifdef CONCURRENT_CONSTRUCT_GRAPH
    my_mutex_unlock(&(t->task_base.over));
    my_mutex_unlock(&(t->task_base.successor_lock));
    decrement_ref_count(&(t->task_base));
#ifdef FAT_TDG
    inc_predecessorCount(&(t->task_base));
#else
    increment_ref_count(&(t->task_base));
#endif
#endif
    // vector_tasks.push_back(t);  // for destroy

    // #if (!defined(SPECIFY_END_TASKS)) || (!defined(NO_END_TASK_LIST))
    // #ifndef FAT_TDG
    //     add_end_task(t);
    // #endif
    // #endif
    // #if defined(ACEMESH_GRAPH_BUILD_PROFILING) && defined(FINE_PROF)
    //     buil_prof[END_TASKS_L] += (rtc() - add_start);
    // #endif

    // #ifdef AUTO_AFFINITY
    //     if (is_master) {
    // #ifdef DISTRIBUTED_SCHEDULER
    //         set_affinity_id(&(t->task_base), total_num_threads);  // modify TODO
    // #else
    //         set_affinity_id(&(t->task_base), MS_SCHED);
    // #endif
    //         is_master = 0;
    // #ifdef DEBUG
    //         printf("register master affinity:%d\n", t->task_base.affinity_id);
    // #endif

    //     } else
    //         set_affinity_id(&(t->task_base), my_affinity.get_affinity_id());
    //         // printf("register affinity:%d\n",t->task_base.affinity_id);
    // #ifdef DEBUG
    // #ifdef SEG_BUFF
    // #ifndef AGENT_COMPU
    //     if (t->task_base.affinity_id == total_num_threads - 1) {
    //         printf("task_affinity error:%d\n", t->task_base.affinity_id);
    //         fflush(stdout);
    //         assert(0);
    //     }
    // #endif
    // #endif
    // #endif
    // #ifdef TEMP_AFFI
    //     t->task_base.bak_affinity_id = t->task_base.affinity_id;
    // #endif
    // #endif
#if defined(ACEMESH_GRAPH_BUILD_PROFILING) && defined(FINE_PROF)
                     unsigned long sub_build_rela_start=rtc();
#endif
    slave_register_access(t);
#if defined(ACEMESH_GRAPH_BUILD_PROFILING) && defined(FINE_PROF)
                    buil_prof[SUB_BUILD_RELA]+=(rtc()-sub_build_rela_start);
#endif
    return ACEMESH_OK;
}
Error_Code slave_add_end_task_of_parent()  // serial
{
    if (local_parent != NULL) {
        struct TaskDataAccesses *parentAccessStruct = slave_getDataAccesses(
            &(((aceMesh_task *)
                  local_parent)->task_base));  // 遍历父任务中的哈希表，最后一层与父任务建边
        HashMap addresses = parentAccessStruct->_subaccessBottomMap;
        HashMapIterator itr = slave_createHashMapIterator(addresses);
        // while (slave_hasNextHashMapIterator(itr)) {
        //     itr = slave_nextHashMapIterator(itr);

        // }
        for (int index = 0; hasNextHashMapIterator(itr);
             index++) {  // 这个地方最后一层子任务与父任务建边是为了向后继父任务传递依赖关系。
            // 迭代取出所有键值对
            itr = nextHashMapIterator(itr);
           // slave_setSuccessor(predecessor, itr->entry->value);
        }
    }
}
Error_Code slave_spawn_and_goout()
{
#ifdef SLAVE_CONSTRUCT_HELEPR
#ifdef DEBUG_PBH
  printf("slave_spawn_and_gooutMYID%d\n",_MYID);
  aceMesh_task *parent_ = (aceMesh_task *)local_parent;
     printf("父任务孩子计数为%d的任务%p\n",parent_->task_base._countdownToBeWokenUp,parent_);
#endif
//给helper的所有buffer发送构图结束消息,即address为空
// for(int i=0;i<64;i++){  //TODO改成多个helper
//  struct slave_help_buff *end_info=remote_ldm(7, (slave_buffer[i]));
int i;
for(i=8;i<HELPER_NUM+8;i++){
 struct slave_help_buff *end_info=remote_ldm(i, (slave_buffer[_MYID]));
#ifdef DEBUG_PBH
printf("给helper%d的%d号buffer发送结束消息\n",i,_MYID);
#endif
  int local_tail=(end_info->tail+1)%HELPER_BUFF_SIZE; 
        //队列满就一直循环等待
        while(end_info->head==local_tail){
            
        }  
        //往环形队列里填充数据
        end_info->base[end_info->tail].item_address=NULL;
        end_info->base[end_info->tail].item_hash=1;
        end_info->base[end_info->tail].item_access=NULL;
        end_info->base[end_info->tail].item_id=1;
        end_info->tail=local_tail;  //尾指针+1
        // printf("*****buffer%d结束消息头指针%d尾指针%d\n",i,end_info->head,end_info->tail);
 //}
}
  
    
    // for (int i = 0; i < 64; i++) {
    //     //告诉从核已经没有需要再注册的任务了
    //     int *status=remote_ldm(i, construct_end);
    //     *status=1;
    //     asm volatile ("memb\n");
    // }
    //     while (1) {  //判断helper从核构图是否结束

    //         int *exit_signal=remote_ldm(7, helper_exited);
    //         asm volatile ("memb\n");
    //         if (*exit_signal== 1) {
    //             break;
    //         }
    //     //}
    // }
    //  printf("告诉从核已经没有需要再注册的任务了\n");
    int exit_helper = 0;
    int exit_num=0;
    int continue_flag=false;
    while (!continue_flag) {  //判断helper从核构图是否结束     
           for(exit_helper=8;exit_helper<(HELPER_NUM+8);exit_helper++){
            // for(j=0;j<NT;j++){
            // printf("exit_helper%d\n",exit_helper);
            //int *exit_signal=remote_ldm(i, helper_exited[_MYID]);
            // int *exit_signal=remote_ldm(i, helper_exited);
            asm volatile ("memb\n");
            if (helper_exited[_MYID]== 1) {
                //exit_num++;
                 //assert(exit_num<=HELPER_NUM);
#ifdef DEBUG_PBH
               printf("exit_helper%dexit_num:%d,buffer%d\n",exit_helper,exit_num,_MYID);
#endif
               
                //break;
            }
        //    }
           }
           assert(exit_helper<=HELPER_NUM+8);
           if(exit_helper==HELPER_NUM+8)
           continue_flag=true;
        //}
    }
        
 printf("subtask_number:%d\n",subtask_num);   
 fflush(stdout);
//  int sub_need_spawn = 0;
    for (int i = 0; i < subtask_num; i++) {
        if(slave_predec_count((struct task *)vector_subtasks[i])== -1){
            need_spawn_subtasks[spawn_subtask_num] = (struct task *)vector_subtasks[i];
            spawn_subtask_num++;
            assert(spawn_subtask_num<=NEED_SPAWN_SUBSIZE);
            // struct task* temptask=(struct task *)vector_subtasks[i];
            // struct task* tempparent=getparent(temptask);
            // printf("父任务%p任务的子任务个数%d\n",tempparent->_countdownToBeWokenUp);
            //int id=temptask->affinity_id;
            // printf("*******任务派生%p\n",(struct task *)vector_subtasks[i]);
       //printf("*******任务%p前驱%d\n",(struct task *)vector_subtasks[i],slave_predec_count((struct task *)vector_subtasks[i]));
            //slave_spawn_to_id((struct task *)vector_subtasks[i]);
            //sub_need_spawn++;
        }
    }
      subtask_num=0;
    //   printf("sub_need_spawn_task_number:%d\n",sub_need_spawn);  
#endif
    //    this->spawn();
    // this->reset_task_graph();
    // slave_add_end_task_of_parent();
    // slave_hashClear(slave_first_level);
// #ifdef ACEMESH_GRAPH_BUILD_PROFILING  //start in first begin_split_task()
//         if(first_nest_graph_spawn==0){ 
//             nest_graph_spawn_start=rtc();
//             first_nest_graph_spawn=1;
//         }
// #endif
// #ifndef SLAVE_CONSTRUCT_HELEPR
#if defined(ACEMESH_GRAPH_BUILD_PROFILING) && defined(FINE_PROF)
        unsigned long sub_clean_spawn=rtc();
#endif 
 printf("need_spawn_subtask_number:%d\n",spawn_subtask_num);   
for (int i = 0; i < spawn_subtask_num; i++) {
          slave_spawn_to_id((struct task *)need_spawn_subtasks[i]);
    }
      spawn_subtask_num=0;
#if defined(ACEMESH_GRAPH_BUILD_PROFILING) && defined(FINE_PROF)
                    buil_prof[SUB_PUSH_SPAWN]+=(rtc()-sub_clean_spawn);
#endif
// #endif
    return ACEMESH_OK;
}

Error_Code slave_spawn_and_wait() {}
